//
// Copyright (C) 2009 Solid State Networks, Inc.  All rights reserved.
//
// This usage of this software is restricted to entities which have signed a license agreement
// with Solid State Networks, Inc.
//
// Licenses are valid for only one PRODUCT usage.  Please see the license agreement for further details.
//

_SSN = function()
{
    this.Launcher = new _Launcher();
    this.Downloader = new _Downloader();
    this.Patcher = new _Patcher();
    this.Language = new _Language();
    this.startTime = new Date().getTime();
    this.isErrorMessageOpen = false;  
    this.apiVersion = 6;
    this.isPaused = false;
    
    this.PACKAGELIST_STATE_INVALID = 0;
    this.PACKAGELIST_STATE_INITIALIZE = 1;
    this.PACKAGELIST_STATE_UPDATE_WAIT = 2;
    this.PACKAGELIST_STATE_UPDATE = 3;
    this.PACKAGELIST_STATE_UPDATE_COMPLETE = 4;
    this.PACKAGELIST_STATE_FAILED = 5;
    this.PATCHER_STATE_INVALID = 0;
    this.PATCHER_STATE_IDLE = 1;
    this.PATCHER_STATE_PREPARE = 2;
    this.PATCHER_STATE_DOWNLOAD = 3;
    this.PATCHER_STATE_WAITFORLIVE = 4;
    this.PATCHER_STATE_PREPROCESS = 5;
    this.PATCHER_STATE_ALLOWRESTART = 6;
    this.PATCHER_STATE_PERFORMRESTART = 7;
    this.PATCHER_STATE_COPY = 8;
    this.PATCHER_STATE_VERIFY = 9;
    this.PATCHER_STATE_DELETE = 10;
    this.PATCHER_STATE_POSTPROCESS = 11;
    this.PATCHER_STATE_SAVE = 12;
    this.PATCHER_STATE_TASKCOMPLETE = 13;
    this.PATCHER_STATE_ALLTASKSCOMPLETE = 14;
    this.PATCHER_STATE_FAILED = 15;
    this.PATCHER_DOWNLOAD_STATE_INVALID = 0;
    this.PATCHER_DOWNLOAD_STATE_INITIALIZE = 1;
    this.PATCHER_DOWNLOAD_STATE_SCAN = 2;
    this.PATCHER_DOWNLOAD_STATE_DOWNLOAD = 3;
    this.PATCHER_DOWNLOAD_STATE_COMPLETE = 4;
    this.PATCHER_DOWNLOAD_STATE_FAILED = 5;
    this.PATCHER_DOWNLOAD_STATE_ABORT = 6;
    this.PATCHER_ERROR_COPY = 0;
    this.PATCHER_ERROR_RETRIEVEPACKAGE = 1;
    this.PATCHER_ERROR_DATAFORMAT = 2;
    this.PATCHER_ERROR_DOWNLOAD = 3;
    this.PATCHER_ERROR_DRM_CONTACT = 4;
    this.PATCHER_ERROR_DRM_AUTH = 5;
    this.PATCHER_ERROR_DRM_PERMISSION = 6;
    this.PATCHER_ERROR_PROCESSLAUNCH = 7;
    this.PATCHER_ERROR_COPY_DIFFSOURCEVERIFY = 8;
    this.PATCHER_ERROR_INSTALLER = 9;
    this.PATCHER_ERROR_DISKSPACE = 10;
    this.PATCHER_ERROR_INVALID = 11;
    this.PACKAGE_DESCRIPTOR_TYPE_INVALID = 0;
    this.PACKAGE_DESCRIPTOR_TYPE_REQUIRED = 1;
    this.PACKAGE_DESCRIPTOR_TYPE_OPTIONAL = 2;

    this.LAUNCHERERRORTYPE_SUCCESS                  = 0;
    this.LAUNCHERERRORTYPE_PROCCESSLAUNCH           = this.PATCHER_ERROR_INVALID + 1;
    this.LAUNCHERERRORTYPE_PROCCESSLAUNCHEXITFAIL   = this.PATCHER_ERROR_INVALID + 2;
    this.LAUNCHERERRORTYPE_PROCCESSLAUNCHTIMEOUT    = this.PATCHER_ERROR_INVALID + 3;
    this.LAUNCHERERRORTYPE_ELEVATIONFAIL            = this.PATCHER_ERROR_INVALID + 4;
    this.LAUNCHERERRORTYPE_ELEVATECOMFAIL           = this.PATCHER_ERROR_INVALID + 5;
    this.LAUNCHERERRORTYPE_WARN_ELEVATIONREQUEST    = this.PATCHER_ERROR_INVALID + 6;
    this.LAUNCHERERRORTYPE_WARN_CUSTOM              = this.PATCHER_ERROR_INVALID + 7;
    this.LAUNCHERERRORTYPE_VERSIONFAIL              = this.PATCHER_ERROR_INVALID + 8;
    this.LAUNCHERERRORTYPE_INVALID                  = this.PATCHER_ERROR_INVALID + 9;
}

_SSN.prototype =
{
    defaultInitializedCallback: function() {
        //SSN.defaultStartDownload();
    },

    defaultConstructHttpTarget: function(url) {
        return url;
    },

    defaultProcessExited: function(appName, exitCode) {
        var launchAppName = SSN.Launcher.expandString(SSN.Launcher.getConfig("Launcher.LaunchApplication.AppName", ""));
        if (launchAppName == appName) {
            SSN.Launcher.restore();

            var optionalPatchDownloadDefault = SSN.Launcher.getConfig("Launcher.OptionalPatchDownloadDefault", "stop").toLowerCase();
            var optionalPatchDownload = SSN.Launcher.getSetting("OptionalPatchDownload", optionalPatchDownloadDefault).toLowerCase();
            if (optionalPatchDownload === "resume") {
                SSN.defaultStartDownload();
            }
        }
    },

    defaultErrorHandler: function(error, time, message) {
        if (!SSN.isErrorMessageOpen) {
            isErrorMessageOpen = true;

            if (error == SSN.PATCHER_ERROR_DRM_CONTACT || error == SSN.PATCHER_ERROR_RETRIEVEPACKAGE || error == SSN.PATCHER_ERROR_DOWNLOAD) {
                // warn but don't raise error ui
                isErrorMessageOpen = false;
            }
            else if (error == SSN.PATCHER_ERROR_COPY || error == SSN.PATCHER_ERROR_DATAFORMAT || error == SSN.PATCHER_ERROR_COPY_DIFFSOURCEVERIFY) {
                alert(SSN.Language.ErrorRestart);
                CloseLauncher();
            }
            else if (error == SSN.PATCHER_ERROR_DRM_AUTH || error == SSN.PATCHER_ERROR_DRM_PERMISSION) {
                alert(SSN.Language.ErrorAuthorization);
                CloseLauncher();
            }
            else if (error == SSN.PATCHER_ERROR_DISKSPACE) {
                alert(SSN.Language.ErrorDiskSpace);
                CloseLauncher();
            }
            else if (error == SSN.LAUNCHERERRORTYPE_WARN_ELEVATIONREQUEST) {
                // the os already warns, so this is redundant
                isErrorMessageOpen = true;
            }
            else {
                alert(SSN.Language.ErrorRestart);
                CloseLauncher();
            }
        }
    },

    defaultTogglePause: function() {
        SSN.isPaused = !SSN.isPaused;
        SSN.defaultRefreshSettings();
    },

    defaultGetDownloadName: function() {
        var name = SSN.Launcher.getConfig("Download.Name", "");
        return name;
    },

    defaultRefreshSettings: function() {
        var name = SSN.defaultGetDownloadName();
        var downloadMode = SSN.Launcher.getConfig("Download.Mode", "downloader").toLowerCase();

        if (SSN.isPaused == true) {
            if (downloadMode == "downloader") {
                SSN.Downloader.setDownloadOptions(name, false, false);
            }
            else {
                SSN.Patcher.setPackageListOptions(name, false, false);
            }
            return;
        }

        var allowP2P = SSN.Launcher.getConfig("Launcher.AllowP2P", "true").toLowerCase() == "true";
        var allowHTTP = SSN.Launcher.getConfig("Launcher.AllowHTTP", "true").toLowerCase() == "true";
        var P2PEnabled = SSN.Launcher.getSetting("P2PEnabled", "true").toLowerCase() == "true";
        var HTTPEnabled = SSN.Launcher.getSetting("HTTPEnabled", "true").toLowerCase() == "true";

        if (downloadMode == "downloader") {
            SSN.Downloader.setDownloadOptions(name, allowP2P == true && P2PEnabled == true, allowHTTP == true && HTTPEnabled == true);
        }
        else {
            SSN.Patcher.setPackageListOptions(name, allowP2P == true && P2PEnabled == true, allowHTTP == true && HTTPEnabled == true);
        }
    },

    defaultStartDownload: function() {
        var downloadMode = SSN.Launcher.getConfig("Download.Mode", "downloader").toLowerCase();

        var name = SSN.defaultGetDownloadName();
        var target = SSN.Launcher.getConfig("Download.Target", "");
        var authUrl = SSN.Launcher.getConfig("Download.AuthorizationUrl", "");
        var outputPath = SSN.Launcher.getConfig("Download.OutputPath", "{Choose}");

        var allowP2P = SSN.Launcher.getConfig("Launcher.AllowP2P", "true").toLowerCase() == "true";
        var allowHTTP = SSN.Launcher.getConfig("Launcher.AllowHTTP", "true").toLowerCase() == "true";
        var P2PEnabled = SSN.Launcher.getSetting("P2PEnabled", "true").toLowerCase() == "true";
        var HTTPEnabled = SSN.Launcher.getSetting("HTTPEnabled", "true").toLowerCase() == "true";

        if (downloadMode == "downloader") {
            SSN.Downloader.addDownload(name, target, outputPath, authUrl);
        }
        else {
            SSN.Patcher.addPackageList(name, target, SSN.Launcher.getDirectory());
        }

        SSN.defaultRefreshSettings();
    },

    defaultStopDownload: function() {
        var downloadMode = SSN.Launcher.getConfig("Download.Mode", "downloader").toLowerCase();
        var name = SSN.defaultGetDownloadName();

        if (downloadMode == "downloader") {
            SSN.Downloader.removeDownload(name);
        }
        else {
            SSN.Patcher.removePackageList(name);
        }
    },

    defaultLaunchApplication: function() {
        var appName = SSN.Launcher.expandString(SSN.Launcher.getConfig("Launcher.LaunchApplication.AppName", ""));
        var args = SSN.Launcher.expandString(SSN.Launcher.getConfig("Launcher.LaunchApplication.Args", ""));
        var currentDirectory = SSN.Launcher.expandString(SSN.Launcher.getConfig("Launcher.LaunchApplication.CurrentDirectory", ""));
        var showWindow = SSN.Launcher.getConfig("Launcher.LaunchApplication.ShowWindow", "true").toLowerCase() == 'true';
        var elevate = SSN.Launcher.getConfig("Launcher.LaunchApplication.Elevate", "false").toLowerCase() == 'true';

        if (appName != "") {
            if (SSN.Launcher.launchProcess(appName, args, currentDirectory, showWindow, elevate) == true) {
                var allowOptionalPatchDownloadConfiguration = SSN.Launcher.getConfig("Launcher.AllowOptionalPatchDownloadConfiguration", "false").toLowerCase() == 'true';
                if (allowOptionalPatchDownloadConfiguration == true) {
                    var optionalPatchDownloadDefault = SSN.Launcher.getConfig("Launcher.OptionalPatchDownloadDefault", "stop").toLowerCase();
                    var optionalPatchDownload = SSN.Launcher.getSetting("OptionalPatchDownload", optionalPatchDownloadDefault).toLowerCase();
                    if (optionalPatchDownload === "resume") {
                        SSN.Launcher.minimize();
                        SSN.defaultStopDownload();
                        return;
                    } else if (optionalPatchDownload === "continue") {
                        SSN.Launcher.minimize();
                        return;
                    }
                }
            }
        }
        CloseLauncher();
    },

    // Launcher Helpers
    canLaunch: function(packageListState, targetDescriptorType, patcherState) {
        var retVal = false;
        switch (packageListState) {
            case SSN.PACKAGELIST_STATE_UPDATE_COMPLETE:
            case SSN.PACKAGELIST_STATE_UPDATE_WAIT:
                retVal = true;
                break;

            case SSN.PACKAGELIST_STATE_INITIALIZE:
            case SSN.PACKAGELIST_STATE_UPDATE:
                if (targetDescriptorType == SSN.PACKAGE_DESCRIPTOR_TYPE_OPTIONAL) {
                    switch (patcherState) {
                        case SSN.PATCHER_STATE_PREPROCESS:
                        case SSN.PATCHER_STATE_COPY:
                        case SSN.PATCHER_STATE_VERIFY:
                        case SSN.PATCHER_STATE_DELETE:
                        case SSN.PATCHER_STATE_POSTPROCESS:
                            break;

                        default:
                            retVal = true;
                            break;
                    }
                }
                break;
        }

        return retVal;
    },

    // Patcher Helpers
    getPatcherCompletePercentage: function(packageListState, patcherState, totalBytes, copyBytesLeft, copyBytesTotal, downloadBytesLeft, scanBytesLeft) {
        totalBytes = Number(totalBytes);
        copyBytesLeft = Number(copyBytesLeft);
        copyBytesTotal = Number(copyBytesTotal);
        downloadBytesLeft = Number(downloadBytesLeft);
        scanBytesLeft = Number(scanBytesLeft);

        if (packageListState == SSN.PACKAGELIST_STATE_UPDATE_COMPLETE) {
            return 1;
        }

        if (packageListState == SSN.PACKAGELIST_STATE_UPDATE) {
            if (patcherState == SSN.PATCHER_STATE_COPY || patcherState == SSN.PATCHER_STATE_VERIFY) {
                if (copyBytesLeft == 0) {
                    return 0;
                }

                return ((copyBytesTotal - copyBytesLeft) / copyBytesTotal).toFixed(2);
            }
            else if (patcherState == SSN.PATCHER_STATE_DELETE || patcherState == SSN.PATCHER_STATE_POSTPROCESS) {
                return 1;
            }
            else {
                if ((totalBytes == 0) && (downloadBytesLeft == 0) && (scanBytesLeft == 0)) {
                    return 0;
                }

                if (totalBytes <= 0) {
                    return 1;
                }

                if (patcherState == SSN.PATCHER_STATE_PREPARE) {
                    return ((totalBytes - scanBytesLeft) / totalBytes).toFixed(2);
                }
                else {
                    return ((totalBytes - downloadBytesLeft) / totalBytes).toFixed(2);
                }
            }
        }

        return 0;
    },

    getPatcherStatusMessage: function(packageListState, active, packageName, currentName, targetName) {
        if (active == false) {
            return '';
        }

        if (packageListState == SSN.PACKAGELIST_STATE_UPDATE) {
            var message = SSN.Language.Updating + ' ' + packageName + ' ';

            if (currentName != '' && targetName != '') {
                message += '(' + currentName + '/' + targetName + ')';
            } else if (targetName != '') {
                message += '(' + targetName + ')';
            }

            return message;
        }


        return '';
    },

    getPatcherDetailStatusMessage: function(packageListState, active, patcherState, totalBytes, copyBytesLeft, copyBytesTotal, downloadBytesLeft, scanBytesLeft, bytesRead, averageIncoming) {
        if (active == false) {
            return SSN.Language.Paused;
        }

        if (packageListState == SSN.PACKAGELIST_STATE_INITIALIZE) {
            return SSN.Language.Retrieving;
        }

        if (packageListState == SSN.PACKAGELIST_STATE_UPDATE_COMPLETE) {
            return SSN.Language.AllComplete;
        }

        if (packageListState == SSN.PACKAGELIST_STATE_INVALID || packageListState == SSN.PACKAGELIST_STATE_FAILED) {
            return SSN.Language.ErrorConnect;
        }

        if (packageListState == SSN.PACKAGELIST_STATE_UPDATE) {
            var percent = SSN.getPatcherCompletePercentage(packageListState, patcherState, totalBytes, copyBytesLeft, copyBytesTotal, downloadBytesLeft, scanBytesLeft);
            percent = (percent * 100).toFixed(0);

            if (patcherState == SSN.PATCHER_STATE_PREPARE) {
                return SSN.Language.Prepare + ' (' + percent + '% ' + SSN.Language.Complete + ')';
            }
            else if (patcherState == SSN.PATCHER_STATE_DOWNLOAD) {
                return SSN.Language.Download + ' (' + percent + '% ' + SSN.Language.Complete + ')';
            }
            else if (patcherState == SSN.PATCHER_STATE_COPY) {
                return SSN.Language.Copying + ' (' + percent + '% ' + SSN.Language.Complete + ')';
            }
            else if (patcherState == SSN.PATCHER_STATE_VERIFY) {
                return SSN.Language.Verifying + ' (' + percent + '% ' + SSN.Language.Complete + ')';
            }
            else if (patcherState == SSN.PATCHER_STATE_DELETE) {
                return SSN.Language.Deleting;
            }
            else if (patcherState == SSN.PATCHER_STATE_POSTPROCESS) {
                return SSN.Language.Installing;
            }
            else if (patcherState == SSN.PATCHER_STATE_ALLTASKSCOMPLETE) {
                return SSN.Language.Finished;
            }
        }

        return '';
    },

    getPatcherBytesLeftMessage: function(packageListState, active, patcherState, downloadBytesLeft) {
        if (active == false || packageListState != SSN.PACKAGELIST_STATE_UPDATE || patcherState != SSN.PATCHER_STATE_DOWNLOAD) {
            return '';
        }

        downloadBytesLeft = Number(downloadBytesLeft);
        var mbLeft = (downloadBytesLeft / (1024 * 1024));
        return mbLeft.toFixed(2) + ' ' + SSN.Language.BytesLeft;
    },

    getPatcherTimeEstimateMessage: function(packageListState, active, patcherState, downloadBytesLeft, bytesRead, averageIncoming) {
        if (active == false || packageListState != SSN.PACKAGELIST_STATE_UPDATE || patcherState != SSN.PATCHER_STATE_DOWNLOAD) {
            return '';
        }
        return SSN.getTimeEstimateMessage(downloadBytesLeft, bytesRead, averageIncoming);
    },

    // Download Helpers
    getDownloadCompletePercentage: function(downloadState, totalBytes, downloadBytesLeft, scanBytesLeft) {
        totalBytes = Number(totalBytes);
        downloadBytesLeft = Number(downloadBytesLeft);
        scanBytesLeft = Number(scanBytesLeft);

        if (downloadState == SSN.PATCHER_DOWNLOAD_STATE_COMPLETE) {
            return 1;
        }
        else if (downloadState == SSN.PATCHER_DOWNLOAD_STATE_SCAN) {
            if ((totalBytes == 0) && (scanBytesLeft == 0)) {
                return 0;
            }
            if (totalBytes <= 0) {
                return 1;
            }
            return ((totalBytes - scanBytesLeft) / totalBytes).toFixed(2);
        }
        else if (downloadState == SSN.PATCHER_DOWNLOAD_STATE_DOWNLOAD) {
            if ((totalBytes == 0) && (downloadBytesLeft == 0)) {
                return 0;
            }
            if (totalBytes <= 0) {
                return 1;
            }
            return ((totalBytes - downloadBytesLeft) / totalBytes).toFixed(2);
        }

        return 0;
    },
    getDownloadDetailStatusMessage: function(downloadState, active, totalBytes, downloadBytesLeft, scanBytesLeft, bytesRead, averageIncoming) {
        if (active == false) {
            return SSN.Language.Paused;
        }

        if (downloadState == SSN.PATCHER_DOWNLOAD_STATE_INITIALIZE) {
            return SSN.Language.Retrieving;
        }

        if (downloadState == SSN.PATCHER_DOWNLOAD_STATE_COMPLETE) {
            return SSN.Language.AllComplete;
        }

        if (downloadState == SSN.PATCHER_DOWNLOAD_STATE_INVALID || downloadState == SSN.PATCHER_DOWNLOAD_STATE_FAILED) {
            return SSN.Language.ErrorConnect;
        }

        var percent = SSN.getDownloadCompletePercentage(downloadState, totalBytes, downloadBytesLeft, scanBytesLeft);
        percent = (percent * 100).toFixed(0);

        if (downloadState == SSN.PATCHER_DOWNLOAD_STATE_SCAN) {
            return SSN.Language.Prepare + ' (' + percent + '% ' + SSN.Language.Complete + ')';
        }
        if (downloadState == SSN.PATCHER_DOWNLOAD_STATE_DOWNLOAD) {
            return SSN.Language.Download + ' (' + percent + '% ' + SSN.Language.Complete + ')';
        }
        return '';
    },

    getDownloadBytesLeftMessage: function(downloadState, active, downloadBytesLeft) {
        if (active == false || downloadState != SSN.PATCHER_DOWNLOAD_STATE_DOWNLOAD) {
            return '';
        }

        downloadBytesLeft = Number(downloadBytesLeft);
        var mbLeft = (downloadBytesLeft / (1024 * 1024));
        return mbLeft.toFixed(2) + ' ' + SSN.Language.BytesLeft;
    },

    getDownloadTimeEstimateMessage: function(downloadState, active, downloadBytesLeft, bytesRead, averageIncoming) {
        if (active == false || downloadState != SSN.PATCHER_DOWNLOAD_STATE_DOWNLOAD) {
            return '';
        }
        return SSN.getTimeEstimateMessage(downloadBytesLeft, bytesRead, averageIncoming);
    },

    getTimeEstimateMessage: function(downloadBytesLeft, bytesRead, averageIncoming) {
        downloadBytesLeft = Number(downloadBytesLeft);
        bytesRead = Number(bytesRead);

        var oneSecond = 1;
        var oneMinute = oneSecond * 60;
        var oneHour = oneMinute * 60;
        var oneDay = oneHour * 24;

        var elapsedSeconds = new Date().getTime() - SSN.startTime;
        elapsedSeconds /= 1000;

        if (elapsedSeconds == 0) {
            return '';
        }

        if ((elapsedSeconds <= 30) || (downloadBytesLeft < (1 << 20))) {
            return SSN.Language.EstimatingTime;
        }

        var startingThroughput = bytesRead / elapsedSeconds;
        var estimatedSeconds = (downloadBytesLeft / ((startingThroughput * 0.90) + (averageIncoming * 0.10)));

        if (estimatedSeconds == Infinity) {
            estimatedSeconds = 0;
        }

        if (estimatedSeconds < oneMinute) {
            return SSN.Language.ShortTimeLeft;
        }

        if (estimatedSeconds > 7 * oneDay) {
            return SSN.Language.LongTimeLeft;
        }

        var timeEstimateString = '';

        var days = (estimatedSeconds / oneDay).toString().split('.')[0];
        estimatedSeconds -= days * oneDay;
        if (days > 0) {
            timeEstimateString += ' ' + days + SSN.Language.DayAbbreviation;
        }

        var hours = (estimatedSeconds / oneHour).toString().split('.')[0];
        estimatedSeconds -= hours * oneHour;
        if (hours > 0) {
            timeEstimateString += ' ' + hours + SSN.Language.HourAbbreviation;
        }

        var minutes = (estimatedSeconds / oneMinute).toString().split('.')[0];
        estimatedSeconds -= minutes * oneMinute;
        if (minutes > 0) {
            timeEstimateString += ' ' + minutes + SSN.Language.MinuteAbbreviation;
        }

        if (timeEstimateString.length > 0)
            return timeEstimateString + ' ' + SSN.Language.Left;

        return SSN.Language.EstimatingTime;
    },

    getTransferSpeedMessage: function(speed) {
        var speedKBps = speed / 1024;
        if (speedKBps <= 0.1) {
            return '0.0 ' + SSN.Language.Speed;
        }

        return speedKBps.toFixed(2) + ' ' + SSN.Language.Speed;
    }
}

function __SSN_getVersion()
{
    return SSN.apiVersion;
}

var SSN = new _SSN();
SSN.Launcher.setLauncherErrorCallback(SSN.defaultErrorHandler);
SSN.Launcher.setProcessExitedCallback(SSN.defaultProcessExited);
SSN.Launcher.setLauncherInitializedCallback(SSN.defaultInitializedCallback);
